#pragma once
/*
 *日志器类的设计
 * */
#include"formatter.hpp"
#include"util.hpp"
#include"level.hpp"
#include <mutex>
#include"sink.hpp"
#include <stdarg.h>
#include"looper.hpp"
#include<unordered_map>
namespace zxlog{
    class Logger{//基类日志器
        public:
        enum class LoggerType{
            SYNC_LOGGER = 0,
            ASYNC_LOGGER
        };
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string& logger_name,zxlog::LogLevel::Value& limit_level,zxlog::Formatter::ptr& formatter,std::vector<zxlog::LogSink::ptr>& sinks)
            :_logger_name(logger_name),
            _limit_level(limit_level),
            _formatter(formatter),
            _sinks(sinks.begin(),sinks.end())
        {}
        void debug(const char* file,size_t line,const char* fmt,... )
        {
            //判断该等级是否该输出
            if(_limit_level > zxlog::LogLevel::Value::DEBUG)return;
            //获取有效载荷
            char* res;
            va_list al;
           va_start(al,fmt);
           int len = vasprintf(&res,fmt,al);
           if(len < 0)
           {
               std::cerr<<"日志格式化信息失败"<<std::endl;
           }
           Serialize(zxlog::LogLevel::Value::DEBUG,file,line,res);
           va_end(al);
        }
        void info(const char* file,size_t line,const char* fmt,... )
        {
            //判断该等级是否该输出
            if(_limit_level > zxlog::LogLevel::Value::INFO)return;
            //获取有效载荷
            char* res;
            va_list al;
           va_start(al,fmt);
           int len = vasprintf(&res,fmt,al);
           if(len < 0)
           {
               std::cerr<<"日志格式化信息失败"<<std::endl;
           }
           Serialize(zxlog::LogLevel::Value::INFO,file,line,res);
           va_end(al);
        }
        void error(const char* file,size_t line,const char* fmt,... )
        {
            //判断该等级是否该输出
            if(_limit_level > zxlog::LogLevel::Value::ERROR)return;
            //获取有效载荷
            char* res;
            va_list al;
           va_start(al,fmt);
           int len = vasprintf(&res,fmt,al);
           if(len < 0)
           {
               std::cerr<<"日志格式化信息失败"<<std::endl;
           }
           Serialize(zxlog::LogLevel::Value::ERROR,file,line,res);
           va_end(al);
        }
        void warn(const char* file,size_t line,const char* fmt,... )
        {
            //判断该等级是否该输出
            if(_limit_level > zxlog::LogLevel::Value::WARN)return;
            //获取有效载荷
            char* res;
            va_list al;
           va_start(al,fmt);
           int len = vasprintf(&res,fmt,al);
           if(len < 0)
           {
               std::cerr<<"日志格式化信息失败"<<std::endl;
           }
           Serialize(zxlog::LogLevel::Value::WARN,file,line,res);
           va_end(al);
        }
        void fatal(const char* file,size_t line,const char* fmt,... )
        {
            //判断该等级是否该输出
            if(_limit_level > zxlog::LogLevel::Value::FATAL)return;
            //获取有效载荷
            char* res;
            va_list al;
           va_start(al,fmt);
           int len = vasprintf(&res,fmt,al);
           if(len < 0)
           {
               std::cerr<<"日志格式化信息失败"<<std::endl;
           }
           Serialize(zxlog::LogLevel::Value::FATAL,file,line,res);
           va_end(al);
        }
      protected:
        virtual void Log(const char*data,size_t len) = 0;//纯虚函数
        void Serialize(zxlog::LogLevel::Value level,const char* file,size_t line,std::string str)
        {
           //封装日志信息
           LogMsg msg(file,line,_logger_name,str,level);
           //格式化日志信息
           std::stringstream ss;
           _formatter->format(ss,msg);
           //落地
           Log(ss.str().c_str(),ss.str().size());
        }
       protected:
        std::mutex _mutex;//对sinks加锁,防止多线程使用同一个日志器
        std::string _logger_name;
        zxlog::LogLevel::Value _limit_level;
        zxlog::Formatter::ptr  _formatter;
        std::vector<zxlog::LogSink::ptr> _sinks;
    };

    //同步日志器
    class SyncLogger:public Logger
    {
        public:
            SyncLogger(const std::string &logger_name,zxlog::LogLevel::Value& limit_level,zxlog::Formatter::ptr& formatter,std::vector<zxlog::LogSink::ptr>& sinks)
                :Logger(logger_name,limit_level,formatter,sinks)
            {}
        private://??????????????????????????????????????????????????????????????
            void Log(const char*data,size_t len) override
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_sinks.empty())return;
                for(auto sink:_sinks)
                {
                    sink->log(data,len);
                }
            }
    };
    //异步日志器
    class AsyncLogger:public Logger
    {
        public:
            AsyncLogger(const std::string &logger_name,zxlog::LogLevel::Value& limit_level,zxlog::Formatter::ptr& formatter,std::vector<zxlog::LogSink::ptr>& sinks,AsyncLooper::AsyncType async_type)
                :Logger(logger_name,limit_level,formatter,sinks),
                //_looper(AsyncLogger::realLog,async_type)
                //_looper([this](Buffer& buf){this->realLog(buf);},async_type)
                 _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), async_type))
            {}
            void Log(const char* data,size_t len)override
            {
                _looper->push(data,len);
            }
            void realLog(Buffer& buf)
            {
                if(_sinks.empty())return;
                for(auto sink:_sinks)
                {
                    sink->log(buf.begin(),buf.readAbleSize());
                }
                //_looper->stop();
            }
        private:
            AsyncLooper::ptr  _looper;
        
    };
    class BuildLogger{
        public:
            using ptr = std::shared_ptr<BuildLogger>;
            BuildLogger(const Logger::LoggerType& logger_type = Logger::LoggerType::SYNC_LOGGER,
                    LogLevel::Value limit_level = LogLevel::Value::DEBUG,AsyncLooper::AsyncType looper_type = AsyncLooper::AsyncType::ASYNC_UNSAFE)
                :_logger_type(logger_type),
                _limit_level(limit_level),
                _looper_type(looper_type)
            {}
            void BuildLoggerType(Logger::LoggerType logger_type){_logger_type = logger_type;}
            void BuildLoggerName(const std::string& logger_name){_logger_name = logger_name;}
            void BuildLoggerLevel(LogLevel::Value level){_limit_level = level;}
            void BuildFormatter(const std::string& pattern){_formatter = std::make_shared<Formatter>(pattern);}
            void BuildLooperType(AsyncLooper::AsyncType looper_type){_looper_type = looper_type;}
            template<class SinkType,class ...Args>
            void BuildSinks(Args&& ... args)
            {
                LogSink::ptr sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
                _sinks.push_back(sink);
            }
            virtual Logger::ptr Builder() = 0;
        protected:
            zxlog::Logger::LoggerType _logger_type;
            AsyncLooper::AsyncType _looper_type;
            std::string _logger_name;
            Formatter::ptr _formatter;
            LogLevel::Value _limit_level;
            std::vector<LogSink::ptr> _sinks;
    };
    class LocalBuildLogger:public BuildLogger{
        public:
            Logger::ptr Builder(){
                assert(!_logger_name.empty());
                if(_formatter.get() == nullptr){
                    _formatter = std::make_shared<Formatter>();
                }
                if(_sinks.empty())
                {
                    BuildSinks<StdoutSink>();
                }
                if(_logger_type == Logger::LoggerType::ASYNC_LOGGER){
                    return std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
                }
                return std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }
    };

//全局日志器管理者
    class LoggerManager{
        public:
            LoggerManager(){
                //创建root日志器
                BuildLogger::ptr logger = std::make_shared<LocalBuildLogger>();
                logger->BuildLoggerName("root");
                _root = logger->Builder();
                _loggers.insert(std::make_pair("root",_root));
            }
            LoggerManager(const LoggerManager& lg) = delete;
            LoggerManager& operator=(const LoggerManager& lg) = delete;
        public:
            //创建单例对象
            static LoggerManager& getInstance()
            {
                static LoggerManager lm;
                return lm;
            }
            //判断有无该名称的日志器
            bool hasLogger(const std::string& name)
            {
                auto it = _loggers.find(name);
                if(it == _loggers.end())
                {
                    return false;
                }
                return true;
            }
            //添加日志器
            void addLogger(const std::string& name,Logger::ptr logger)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _loggers.insert(std::make_pair(name,logger));
            }
            //获得日志器
            Logger::ptr getLogger(const std::string& name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(!hasLogger(name))return Logger::ptr();
                return _loggers[name];
            }
            //获取root日志器
            Logger::ptr rootLogger()
            {
                std::unique_lock<std::mutex> lock(_mutex);
                return _root;
            }
        private:
            std::mutex _mutex;
            Logger::ptr _root;//提供一个日志器，便于用户直接使用，不用再创建了
            std::unordered_map<std::string,Logger::ptr> _loggers;
    };
    //全局日志器的建造者
    class GlobalBuildLogger:public BuildLogger{
        public:
            Logger::ptr Builder()override
            {
                assert(!_logger_name.empty());
                //判断该日志器是否在单例管理对象中，有则不添加
                assert(LoggerManager::getInstance().hasLogger(_logger_name) == false);
                if(_formatter.get() == nullptr){
                    _formatter = std::make_shared<Formatter>();
                }
                if(_sinks.empty())
                {
                    BuildSinks<StdoutSink>();
                }
                Logger::ptr it;//只声明，不初始化
                if(_logger_type == Logger::LoggerType::ASYNC_LOGGER){
                    it = std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
                }else
                {
                    it = std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
                }
                LoggerManager::getInstance().addLogger(_logger_name,it);
                return it;
            }
    };
}

























